home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / aplictns / graph.4 < prev    next >
Internet Message Format  |  1989-11-13  |  59KB

  1. Path: xanth!lll-winken!uunet!wuarchive!texbell!texsun!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i207:  graph - plot mathematical functions, Part04/07
  5. Message-ID: <127785@sun.Eng.Sun.COM>
  6. Date: 13 Nov 89 02:32:34 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1878
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
  12. Posting-number: Volume 89, Issue 207
  13. Archive-name: applications/graph.4
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    graphics.h
  24. #    grph.c
  25. # This is archive 4 of a 7-part kit.
  26. # This archive created: Sun Nov 12 18:23:30 1989
  27. echo "extracting graphics.h"
  28. sed 's/^X//' << \SHAR_EOF > graphics.h
  29. X/*
  30. X *                 GRAPH, Version 1.00 - 4 August 1989
  31. X *
  32. X *            Copyright 1989, David Gay. All Rights Reserved.
  33. X *            This software is freely redistrubatable.
  34. X */
  35. X
  36. X/* Various graphic extensions */
  37. X#ifndef BIG_GRAPHICS_H
  38. X#define BIG_GRAPHICS_H
  39. X
  40. X/* Now, where did I get this idea ??? */
  41. Xstruct TextExtent {
  42. X    UWORD te_Width;
  43. X    UWORD te_Height;
  44. X    struct Rectangle te_Extent;
  45. X};
  46. X
  47. X/* Draw a line longer than 1008 pixels */
  48. Xvoid BigDraw(struct RastPort *rp, long x, long y);
  49. X/* Idem, but take account of PenWidth, PenHeight (must be odd) */
  50. Xvoid ThickDraw(struct RastPort *rp, long x, long y);
  51. X/* Only works for rastport's with no clipping */
  52. Xvoid BigSetRast(struct RastPort *rp, long colour);
  53. X/* Determine real extent of text(-> Rectangle), return it in TextExtent ext */
  54. Xvoid TextExtent(char *text, struct TextFont *font, struct TextExtent *ext);
  55. X
  56. X#endif
  57. X
  58. SHAR_EOF
  59. echo "extracting grph.c"
  60. sed 's/^X//' << \SHAR_EOF > grph.c
  61. X/*
  62. X *                 GRAPH, Version 1.00 - 4 August 1989
  63. X *
  64. X *            Copyright 1989, David Gay. All Rights Reserved.
  65. X *            This software is freely redistrubatable.
  66. X */
  67. X
  68. X/* Graph manipulation */
  69. X
  70. X#include <exec/types.h>
  71. X#include <graphics/gfxbase.h>
  72. X#include <graphics/rastport.h>
  73. X#include <intuition/intuition.h>
  74. X#include <devices/prtbase.h>
  75. X#include <devices/printer.h>
  76. X#include <stdio.h>
  77. X#include <string.h>
  78. X#include <math.h>
  79. X#include <limits.h>
  80. X#include <iff/iff.h>
  81. X#include <iff/ilbm.h>
  82. X
  83. X#include "grph.h"
  84. X#include "file.h"
  85. X#include "graphics.h"
  86. X#include "graph.h"
  87. X#include "uio.h"
  88. X#include "object.h"
  89. X#include "list.h"
  90. X#include "coords.h"
  91. X#include "user/gadgets.h"
  92. X#include "tracker.h"
  93. X
  94. X#include <proto/exec.h>
  95. X#include <proto/graphics.h>
  96. X#include <proto/diskfont.h>
  97. X#include <proto/intuition.h>
  98. X
  99. X#define INCH 2.54e-2
  100. X#define DIGHEIGHT 8   /* Digit font size, in points (1 point = 1/72 inch) */
  101. X#define XTICK 0.05    /* Size of tick for X axis, In inches */
  102. X#define YTICK 0.05
  103. X#define XTEXT 0.12
  104. X#define YTEXT 0.09
  105. X
  106. X#define MAXPRINTPAGES 1 /* Max length for printing */
  107. X#define CHOOSELIST 2    /* for choose req */
  108. X#define IFFDISK 2       /* For iff req */
  109. X
  110. X/* A function to send a slice of output to the chosen device (disk/file) */
  111. Xtypedef int (*prtfunc)(struct graph *g, struct RastPort *rp, int w, int h, int
  112. Xy, int slice, struct Requester *abreq);
  113. X
  114. Xextern struct GfxBase *GfxBase;
  115. X
  116. Xstatic UWORD scr_dpmx, scr_dpmy; /* The screen 'resolution' */
  117. X
  118. X/* Data for printer output */
  119. Xstatic struct IODRPReq *prtio;
  120. Xstatic struct MsgPort *prtport;
  121. Xstatic struct PrinterExtendedData *ped;
  122. Xstatic struct Preferences *prtprefs;
  123. Xstatic struct ColorMap *prtcm;
  124. X
  125. X/* Data for iff output */
  126. Xstatic FILE *iff_file;
  127. Xstatic long form_pos, body_pos;
  128. Xstatic char iff_filename[FILELEN];
  129. Xstatic struct Gadget *iffg;
  130. X
  131. Xstatic char *prt_error[] = {
  132. X    "Unknown error",
  133. X    "Print cancelled",
  134. X    "Not a graphics printer !",
  135. X    "Obsolete",
  136. X    "Illegal print dimensions",
  137. X    "Obsolete",
  138. X    "No memory (internal)",
  139. X    "No memory (for buffers)"
  140. X};
  141. X
  142. X#define MAX_PRT_ERROR (sizeof(prt_error) / sizeof(char *) - 1)
  143. X
  144. X/* Check that ax can be displayed */
  145. Xstatic int ax_ok(const struct ax *a, const struct ax *other)
  146. X{
  147. X    return (a->ax == NOVAL ||
  148. X             ((!other->log || a->ax > 0.0) &&
  149. X               (a->cstep == NOVAL ||
  150. X                 (a->cstep > 0.0 &&
  151. X                   (a->every == INOVAL || a->every > 0)))));
  152. X}
  153. X
  154. X/* Check that ax has legal values */
  155. Xstatic int ax_ok2(const struct ax *a)
  156. X{
  157. X    return a->min != NOVAL && a->max != NOVAL && a->min < a->max &&
  158. X           (!a->log || a->min > 0.0);
  159. X}
  160. X
  161. X/* Check if graph is displayable */
  162. Xstatic int graph_ok(struct graph *g)
  163. X{
  164. X    g->a.ok = ax_ok(&g->a.x, &g->a.y) && ax_ok(&g->a.y, &g->a.x) &&
  165. X              (g->a.ratio == NOVAL || g->a.ratio > 0.0);
  166. X
  167. X    return ax_ok2(&g->a.x) && ax_ok2(&g->a.x);
  168. X}
  169. X
  170. X/* Redraw graph after changes */
  171. Xstatic void check_graph(struct graph *g)
  172. X{
  173. X    g->saved = FALSE;
  174. X    g->ok = graph_ok(g);
  175. X    set_scale(g);
  176. X    draw_graph(g, TRUE);
  177. X}
  178. X
  179. X/* Find object in graph by name */
  180. Xstatic struct object *find_object(struct graph *g, char *name)
  181. X{
  182. X    struct object *o;
  183. X
  184. X    for (o = first(&g->o_list); succ(o); o = succ(o))
  185. X        if (strcmp(o->name, name) == 0) return o;
  186. X
  187. X    return NULL;
  188. X}
  189. X
  190. X/* Convert inches to rastport dots, using current dpm */
  191. X/* Use integer arithmetic if needs to be called often */
  192. Xint xinch2dots(struct graph *g, double x)
  193. X{
  194. X    return (int)(x * INCH * g->io.dpmx + 0.5);
  195. X}
  196. X
  197. Xint yinch2dots(struct graph *g, double y)
  198. X{
  199. X    return (int)(y * INCH * g->io.dpmy + 0.5);
  200. X}
  201. X
  202. X/* Open font in pts points */
  203. Xstruct TextFont *open_font(struct graph *g, char *name, int pts, int style, int
  204. X flags)
  205. X{
  206. X    struct TextAttr ta;
  207. X    struct TextFont *tf1, *tf2;
  208. X
  209. X    ta.ta_Name = name;
  210. X    ta.ta_YSize = yinch2dots(g, pts / 72.0);
  211. X    ta.ta_Style = style;
  212. X    ta.ta_Flags = flags;
  213. X
  214. X    tf1 = OpenFont(&ta);
  215. X    if (!tf1)
  216. X        return OpenDiskFont(&ta);
  217. X    else if (tf1->tf_YSize != ta.ta_YSize)
  218. X    {
  219. X        tf2 = OpenDiskFont(&ta);
  220. X
  221. X        if (tf2)
  222. X        {
  223. X            CloseFont(tf1);
  224. X            return tf2;
  225. X        }
  226. X        else
  227. X            return tf2;
  228. X    }
  229. X    else
  230. X        return tf1;
  231. X}
  232. X
  233. X/* add object to graph (object is already displayed) */
  234. Xstruct object *add_object(struct graph *g, struct object *o)
  235. X{
  236. X    if (o)
  237. X    {
  238. X        if (o->name[0] != '\0' && find_object(g, o->name))
  239. X        {
  240. X            message(g, "Name already used", (char *)NULL);
  241. X            refresh_graph(g, TRUE, o->delete(o));
  242. X            return NULL;
  243. X        }
  244. X        add_head(&g->o_list, o);
  245. X        g->saved = FALSE;
  246. X    }
  247. X    return o;
  248. X}
  249. X
  250. X/* Remove object & redisplay graph */
  251. Xvoid remove_object(struct graph *g, struct object *o)
  252. X{
  253. X    if (o == g->s.current)
  254. X    {
  255. X        o->deselect(o);
  256. X        g->s.current = NULL;
  257. X        disable_rect_menus(g);
  258. X        disable_object_menus(g);
  259. X    }
  260. X    remove(o);
  261. X    g->saved = FALSE;
  262. X    refresh_graph(g, TRUE, o->delete(o));
  263. X}
  264. X
  265. X/* Make object o selected */
  266. Xvoid select_object(struct graph *g, struct object *o)
  267. X{
  268. X    if (o)
  269. X    {
  270. X        g->s.current = o;
  271. X        o->select(o); /* Inform object of this */
  272. X        enable_object_menus(g);
  273. X        set_title(g);
  274. X    }
  275. X}
  276. X
  277. X/* Deslect current object */
  278. Xvoid deselect(struct graph *g)
  279. X{
  280. X    struct Region *ref;
  281. X
  282. X    /* Deselect object */
  283. X    ref = g->s.current ? g->s.current->deselect(g->s.current) : NULL;
  284. X    g->s.current = NULL;
  285. X
  286. X    disable_rect_menus(g);
  287. X    disable_object_menus(g);
  288. X    refresh_graph(g, TRUE, ref);
  289. X}
  290. X
  291. X/* User pressed mouse button */
  292. Xvoid mouse_down(struct graph *g, WORD sx, WORD sy)
  293. X{
  294. X    if (g->ok && g->io.rw)
  295. X    {
  296. X        /* Get real pos */
  297. X        g->s.x = g->io.rw->x(g->io.rw, sx);
  298. X        g->s.y = g->io.rw->y(g->io.rw, sy);
  299. X        /* If nothing selected, or if not clicking in selected object */
  300. X        if (!g->s.current || !g->s.current->down(g->s.current))
  301. X        {
  302. X            deselect(g);
  303. X
  304. X            if (g->s.select_mode) /* Try to select something */
  305. X            {
  306. X                struct object *o;
  307. X
  308. X                for (o = first(&g->o_list); succ(o); o = succ(o))
  309. X                    if (o->down(o)) /* Inside object ? */
  310. X                    {
  311. X                        select_object(g, o);
  312. X                        break; /* exit for loop */
  313. X                    }
  314. X            }
  315. X            else /* Start a new rectangle */
  316. X                if (g->s.current = (struct object *)new_pos(g))
  317. X                    enable_rect_menus(g);
  318. X
  319. X        }
  320. X        if (g->s.current) /* Something is now selected, keep track of mouse */
  321. X        {
  322. X            /* Adjust position for offset in object */
  323. X            g->s.x = g->io.rw->x(g->io.rw, sx - g->s.current->mx);
  324. X            g->s.y = g->io.rw->y(g->io.rw, sy - g->s.current->my);
  325. X            ReportMouse(g->io.win, TRUE);
  326. X            g->s.mouse = TRUE;
  327. X        }
  328. X        set_title(g);
  329. X    }
  330. X}
  331. X
  332. X/* Mouse has moved */
  333. Xvoid mouse_move(struct graph *g, WORD sx, WORD sy)
  334. X{
  335. X    if (g->s.mouse)
  336. X    {
  337. X        /* Adjust for offset, calc pos in coord system */
  338. X        sx -= g->s.current->mx;
  339. X        sy -= g->s.current->my;
  340. X        g->s.x = g->io.rw->x(g->io.rw, sx);
  341. X        g->s.y = g->io.rw->y(g->io.rw, sy);
  342. X
  343. X        /* Inform selection of movement */
  344. X        g->s.current->move(g->s.current);
  345. X
  346. X        set_title(g);
  347. X    }
  348. X}
  349. X
  350. X/* Mouse button released */
  351. Xvoid mouse_up(struct graph *g, WORD sx, WORD sy)
  352. X{
  353. X    if (g->s.mouse) /* mouse was down */
  354. X    {
  355. X        g->saved = FALSE;  ./* Graph has very probably changed */
  356. X        g->s.mouse = FALSE;
  357. X
  358. X        sx -= g->s.current->mx;
  359. X        sy -= g->s.current->my;
  360. X        g->s.x = g->io.rw->x(g->io.rw, sx);
  361. X        g->s.y = g->io.rw->y(g->io.rw, sy);
  362. X
  363. X        ReportMouse(g->io.win, FALSE);
  364. X        /* Redaw whatever is necessary */
  365. X        refresh_graph(g, TRUE, g->s.current->up(g->s.current));
  366. X    }
  367. X}
  368. X
  369. X/* Handler for object selection requester */
  370. Xstatic int choose_handler(struct Gadget *gg, ULONG class, struct Requester *req
  371. X, struct graph *g)
  372. X{
  373. X    if (gg->GadgetID == CHOOSELIST) /* In a list */
  374. X    {
  375. X        if (ModifyList(gg, req, req->RWindow, class == GADGETUP) == 2)
  376. X        {
  377. X            EndRequest(req, req->RWindow);
  378. X            return TRUE;
  379. X        }
  380. X    }
  381. X    else return std_ghandler(gg, class, req, g);
  382. X}
  383. X
  384. X/* Ask user to choose an object, by name */
  385. Xstruct object *choose_object(struct graph *g, char *op)
  386. X{
  387. X    struct object *o, *sel = NULL;
  388. X    char name[FNAMELEN];
  389. X    tlist l;
  390. X    char what[30];
  391. X    int ok;
  392. X
  393. X    /* Construct title */
  394. X    what[29] = '\0'; name[0] = '\0';
  395. X    strncpy(what, op, 29);
  396. X    strncat(what, " function", 29 - strlen(what));
  397. X
  398. X    /* Construct list of named objects */
  399. X    new_list(&l);
  400. X    ok = TRUE;
  401. X    for (o = first(&g->o_list); succ(o); o = succ(o))
  402. X        if (o->name[0] != '\0')
  403. X        {
  404. X            tnode *n = alloc_node(sizeof(tnode));
  405. X
  406. X            if (!n)
  407. X            {
  408. X                ok = FALSE;
  409. X                break;
  410. X            }
  411. X            n->ln_Name = o->name;
  412. X            add_tail(&l, n);
  413. X        }
  414. X
  415. X    if (ok) /* list constructed ok */
  416. X    {
  417. X        /* Create requester */
  418. X        struct Requester *req;
  419. X        struct Memory *m;
  420. X        struct Gadget *gl = NULL;
  421. X
  422. X        if ((m = NewMemory()) &&
  423. X            (req = InitReq(50, 20, 200, 120, m)) &&
  424. X            SetReqBorder(req, 1, m) &&
  425. X            AddIntuiText(&req->ReqText, what, 100 - 4 * strlen(what), 6, m) &&
  426. X            AddList(&gl, CHOOSELIST, "Name", &l, name, FNAMELEN, 0, RELVERIFY |
  427. X ENDGADGET, 20, 20, 160, 80, TRUE, m) &&
  428. X            AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 18, 95, 65, 15, F
  429. XALSE, m) &&
  430. X            AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 118, 95, 65,
  431. X 15, FALSE, m))
  432. X        {
  433. X            SetReqGadgets(req, gl);
  434. X            if (DoRequest(req, g, choose_handler))
  435. X            {
  436. X                /* Remove blanks */
  437. X                strip(name);
  438. X                if (*name)
  439. X                {
  440. X                    sel = find_object(g, name);
  441. X                    if (!sel) message(g, "No such function", (char *)NULL);
  442. X                }
  443. X            }
  444. X        }
  445. X        Free(m);
  446. X    }
  447. X    free_list((list *)&l, sizeof(tnode));
  448. X    return sel;
  449. X}
  450. X
  451. X/* Define coordinate system */
  452. Xvoid enter_limits(struct graph *g)
  453. X{
  454. X    struct Requester *req;
  455. X    struct Memory *m;
  456. X    struct Gadget *gl = NULL, *x_log, *y_log;
  457. X    char xmin[NBLEN], xmax[NBLEN], ymin[NBLEN], ymax[NBLEN], ratio[NBLEN];
  458. X
  459. X    double2str(xmin, g->a.x.min);
  460. X    double2str(xmax, g->a.x.max);
  461. X    double2str(ymin, g->a.y.min);
  462. X    double2str(ymax, g->a.y.max);
  463. X    double2str(ratio, g->a.ratio);
  464. X
  465. X    if ((m = NewMemory()) &&
  466. X        (req = InitReq(50, 20, 325, 105, m)) &&
  467. X        SetReqBorder(req, 1, m) &&
  468. X        AddIntuiText(&req->ReqText, "Limits", 138, 6, m) &&
  469. X        AddText(&gl, 0, "X: Min ", FALSE, xmin, NBLEN, TRUE, 0, RELVERIFY, 67,
  470. X20, 80, 10, TRUE, m) &&
  471. X        AddText(&gl, 0, "Max ", FALSE, xmax, NBLEN, TRUE, 0, RELVERIFY, 190, 20
  472. X, 80, 10, TRUE, m) &&
  473. X        (x_log = AddOption(&gl, 0, "Log", FALSE, g->a.x.log * SELECTED, 0, 305,
  474. X 20, 10, 10, m)) &&
  475. X        AddText(&gl, 0, "Y: Min ", FALSE, ymin, NBLEN, TRUE, 0, RELVERIFY, 67,
  476. X40, 80, 10, TRUE, m) &&
  477. X        AddText(&gl, 0, "Max ", FALSE, ymax, NBLEN, TRUE, 0, RELVERIFY, 190, 40
  478. X, 80, 10, TRUE, m) &&
  479. X        (y_log = AddOption(&gl, 0, "Log", FALSE, g->a.y.log * SELECTED, 0, 305,
  480. X 40, 10, 10, m)) &&
  481. X        AddText(&gl, 0, "Ratio (Y/X) ", FALSE, ratio, NBLEN, TRUE, 0, RELVERIFY
  482. X, 107, 60, 80, 10, TRUE, m) &&
  483. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 49, 80, 65, 15, FALSE
  484. X, m) &&
  485. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 211, 80, 65, 15,
  486. X FALSE, m))
  487. X    {
  488. X        SetReqGadgets(req, gl);
  489. X        if (DoRequest(req, g, std_ghandler))
  490. X        {
  491. X            g->a.x.min = str2double(xmin);
  492. X            g->a.x.max = str2double(xmax);
  493. X            g->a.x.log = (x_log->Flags & SELECTED) != 0;
  494. X            g->a.y.min = str2double(ymin);
  495. X            g->a.y.max = str2double(ymax);
  496. X            g->a.y.log = (y_log->Flags & SELECTED) != 0;
  497. X            g->a.ratio = str2double(ratio);
  498. X            check_graph(g);
  499. X        }
  500. X    }
  501. X    Free(m);
  502. X}
  503. X
  504. X/* Choose axes display options */
  505. Xvoid enter_axes(struct graph *g)
  506. X{
  507. X    struct Requester *req;
  508. X    struct Memory *m;
  509. X    struct Gadget *gl = NULL;
  510. X    char ax_x[NBLEN], ax_y[NBLEN], step_x[NBLEN], step_y[NBLEN],
  511. X         every_x[INTLEN], every_y[INTLEN];
  512. X
  513. X    double2str(ax_x, g->a.x.ax);
  514. X    double2str(step_x, g->a.x.cstep);
  515. X    int2str(every_x, g->a.x.every);
  516. X    double2str(ax_y, g->a.y.ax);
  517. X    double2str(step_y, g->a.y.cstep);
  518. X    int2str(every_y, g->a.y.every);
  519. X
  520. X    if ((m = NewMemory()) &&
  521. X        (req = InitReq(50, 15, 225, 165, m)) &&
  522. X        SetReqBorder(req, 1, m) &&
  523. X        AddIntuiText(&req->ReqText, "Axes", 96, 6, m) &&
  524. X        AddText(&gl, 0, "X: Axe at ", FALSE, ax_x, NBLEN, TRUE, 0, RELVERIFY, 9
  525. X1, 20, 80, 10, TRUE, m) &&
  526. X        AddText(&gl, 0, "   Ticks every ", FALSE, step_x, NBLEN, TRUE, 0, RELVE
  527. XRIFY, 131, 40, 80, 10, TRUE, m) &&
  528. X        AddText(&gl, 0, "   numbered every ", FALSE, every_x, INTLEN, TRUE, 0,
  529. XRELVERIFY, 155, 60, 32, 10, TRUE, m) &&
  530. X        AddText(&gl, 0, "Y: Axe at ", FALSE, ax_y, NBLEN, TRUE, 0, RELVERIFY, 9
  531. X1, 80, 80, 10, TRUE, m) &&
  532. X        AddText(&gl, 0, "   Ticks every ", FALSE, step_y, NBLEN, TRUE, 0, RELVE
  533. XRIFY, 131, 100, 80, 10, TRUE, m) &&
  534. X        AddText(&gl, 0, "   numbered every ", FALSE, every_y, INTLEN, TRUE, 0,
  535. XRELVERIFY, 155, 120, 32, 10, TRUE, m) &&
  536. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 24, 140, 65, 15, FALS
  537. XE, m) &&
  538. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 136, 140, 65, 15
  539. X, FALSE, m))
  540. X    {
  541. X        SetReqGadgets(req, gl);
  542. X        if (DoRequest(req, g, std_ghandler))
  543. X        {
  544. X            g->a.x.ax = str2double(ax_x);
  545. X            g->a.x.cstep = str2double(step_x);
  546. X            g->a.x.every = str2int(every_x);
  547. X            g->a.y.ax = str2double(ax_y);
  548. X            g->a.y.cstep = str2double(step_y);
  549. X            g->a.y.every = str2int(every_y);
  550. X            check_graph(g);
  551. X        }
  552. X    }
  553. X    Free(m);
  554. X}
  555. X
  556. X/* Change mode */
  557. Xvoid set_mode(struct graph *g, int newmode)
  558. X{
  559. X    if (newmode != g->s.select_mode) deselect(g);
  560. X    g->s.select_mode = newmode;
  561. X}
  562. X
  563. X/* Recalc & display title */
  564. X/* assumes GNAMELEN < TITLELEN */
  565. Xvoid set_title(struct graph *g)
  566. X{
  567. X    strcpy(g->io.title, g->name);
  568. X    if (!g->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 - strlen(g->io.title
  569. X));
  570. X    if (g->s.current)
  571. X        if (g->s.current->name[0] != '\0')
  572. X        {
  573. X            strncat(g->io.title, ", function is ", TITLELEN - 1 - strlen(g->io.
  574. Xtitle));
  575. X            strncat(g->io.title, g->s.current->name, TITLELEN - 1 - strlen(g->i
  576. Xo.title));
  577. X            if (!g->s.current->ok) strncat(g->io.title, "(Bad)", TITLELEN - 1 -
  578. X strlen(g->io.title));
  579. X        }
  580. X        else strncat(g->io.title, ", object selected", TITLELEN -1 - strlen(g->
  581. Xio.title));
  582. X    else strncat(g->io.title, ", nothing selected", TITLELEN - 1 - strlen(g->io
  583. X.title));
  584. X    if (g->s.mouse)
  585. X    {
  586. X        char x[NBLEN], y[NBLEN];
  587. X
  588. X        double2str(x, g->s.x); double2str(y, g->s.y);
  589. X        strncat(g->io.title, "  x=", TITLELEN - 1 - strlen(g->io.title));
  590. X        strncat(g->io.title, x, TITLELEN - 1 - strlen(g->io.title));
  591. X        strncat(g->io.title, ", y=", TITLELEN - 1 - strlen(g->io.title));
  592. X        strncat(g->io.title, y, TITLELEN - 1 - strlen(g->io.title));
  593. X    }
  594. X
  595. X    SetWindowTitles(g->io.win, g->io.title, "Graph");
  596. X}
  597. X
  598. X/* Window has changed size, recreate coord system, taking into account the
  599. X   desired ratio */
  600. Xvoid set_scale(struct graph *g)
  601. X{
  602. X    /* Standard borders */
  603. X    long x0offset = g->io.win->BorderLeft + 8;
  604. X    long x1offset = g->io.win->BorderRight + 8;
  605. X    long y0offset = g->io.win->BorderBottom + 8;
  606. X    long y1offset = g->io.win->BorderTop + 8;
  607. X
  608. X    /* Save size used */
  609. X    g->io.oldwidth = g->io.win->Width; g->io.oldheight = g->io.win->Height;
  610. X
  611. X    /* Delete old coords */
  612. X    if (g->io.rw) g->io.rw->delete(g->io.rw);
  613. X
  614. X    /* Create new coords at max size */
  615. X    g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->Heigh
  616. Xt,
  617. X                          x0offset, y0offset, x1offset, y1offset,
  618. X                          g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
  619. X                          g->a.x.log, g->a.y.log, TRUE);
  620. X    if (!g->io.rw)
  621. X    {
  622. X        message(g, "Couldn't make coords", (char *)NULL);
  623. X        return;
  624. X    }
  625. X
  626. X    SetRast(g->io.win->RPort, 0); /* Clear whole window */
  627. X
  628. X    if (g->ok && g->a.ok && g->a.ratio != NOVAL)
  629. X    {
  630. X        /* Adjust for desired ratio */
  631. X        double r;
  632. X
  633. X        /* Current ratio */
  634. X        r = g->a.ratio /
  635. X            fabs(((g->io.rw->sy(g->io.rw, g->a.y.log ? 10.0 : 2.0) - g->io.rw->
  636. Xsy(g->io.rw, 1.0)) * scr_dpmx) /
  637. X                 ((g->io.rw->sx(g->io.rw, g->a.x.log ? 10.0 : 2.0) - g->io.rw->
  638. Xsx(g->io.rw, 1.0)) * scr_dpmy));
  639. X
  640. X        g->io.rw->delete(g->io.rw);
  641. X
  642. X        /* Adjust borders */
  643. X        if (r > 1.0) /* make X smaller */
  644. X        {
  645. X            long width = g->io.win->Width - x0offset - x1offset;
  646. X            long delta = width - width / r;
  647. X
  648. X            x0offset += delta / 2;
  649. X            x1offset += delta - delta / 2;
  650. X        }
  651. X        else /* make Y smaller */
  652. X        {
  653. X            long height = g->io.win->Height - y0offset - y1offset;
  654. X            long delta = height - height * r;
  655. X
  656. X            y0offset += delta / 2;
  657. X            y1offset += delta - delta / 2;
  658. X        }
  659. X        /* & create new coord system */
  660. X        g->io.rw = new_RWindow(g->io.win->RPort, g->io.win->Width, g->io.win->H
  661. Xeight,
  662. X                               x0offset, y0offset, x1offset, y1offset,
  663. X                               g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
  664. X                               g->a.x.log, g->a.y.log, TRUE);
  665. X        if (!g->io.rw)
  666. X        {
  667. X            message(g, "Couldn't make coords", (char *)NULL);
  668. X            return;
  669. X        }
  670. X    }
  671. X}
  672. X
  673. X/* Change output resolution.
  674. X   This may require opening of new resources (eg fonts) in the objects, which
  675. X   can obviously fail, yet we don't want the graph to be left in an inconsis-
  676. X   tent state, hence inform & confirm (cf object.guidelines). */
  677. Xint set_dpm(struct graph *g, int dpmx, int dpmy)
  678. X{
  679. X    int olddpmx = g->io.dpmx, olddpmy = g->io.dpmy;
  680. X    struct TextFont *digits;
  681. X
  682. X    g->io.dpmx = dpmx; g->io.dpmy = dpmy;
  683. X    /* Open correct font for this resolution */
  684. X    if (digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
  685. X    {
  686. X        int ok = TRUE;
  687. X        struct object *scan, *scan2;
  688. X
  689. X        /* Inform objects */
  690. X        for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
  691. X            if (!scan->inform(scan)) ok = FALSE;
  692. X
  693. X        if (ok)
  694. X        {
  695. X            /* Everything worked, confoirm changes */
  696. X            for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
  697. X     
  698. X                scan->confirm(scan, TRUE);
  699. X
  700. X            /* Free old resources */
  701. X            CloseFont(g->io.digits);
  702. X            g->io.digits = digits;
  703. X            return TRUE;
  704. X        }
  705. X        /* Return to previous state */
  706. X        for (scan2 = first(&g->o_list); scan2 != scan; scan2 = succ(scan2))
  707. X            scan2->confirm(scan2, FALSE);
  708. X
  709. X        CloseFont(digits);
  710. X    }
  711. X    else
  712. X        message(g, "Couldn't open digits.font", (char *)NULL);
  713. X    g->io.dpmx = olddpmx; g->io.dpmy = olddpmy;
  714. X    return FALSE;
  715. X}
  716. X
  717. X    /* Set pen to one ptsize wide. Should really modify g->io.rw->rp, but ... *
  718. X/
  719. Xvoid set_pensize(struct graph *g, struct RastPort *rp, double ptsize)
  720. X{
  721. X    int xsize = xinch2dots(g, ptsize / 72.0);
  722. X    int ysize = yinch2dots(g, ptsize / 72.0);
  723. X
  724. X    if ((xsize & 1) == 0) xsize++;
  725. X    if ((ysize & 1) == 0) ysize++;
  726. X
  727. X    rp->PenWidth = xsize;
  728. X    rp->PenHeight = ysize;
  729. X}
  730. X
  731. X/* Use a "thin" line (1 pixel wide) */
  732. Xvoid set_thin(struct graph *g, struct RastPort *rp)
  733. X{
  734. X    rp->PenWidth = 1;
  735. X    rp->PenWidth = 1;
  736. X}
  737. X
  738. X/* Change graph limits */
  739. Xvoid zoom_in(struct graph *g, double x0, double y0, double x1, double y1)
  740. X{
  741. X    if (g->ok && x0 != x1 && y0 != y1)
  742. X    {
  743. X        double xmin = min(x0, x1);
  744. X        double xmax = max(x0, x1);
  745. X        double ymin = min(y0, y1);
  746. X        double ymax = max(y0, y1);
  747. X
  748. X        g->a.x.min = max(g->a.x.min, xmin);
  749. X        g->a.x.max = min(g->a.x.max, xmax);
  750. X        g->a.y.min = max(g->a.y.min, ymin);
  751. X        g->a.y.max = min(g->a.y.max, ymax);
  752. X
  753. X        check_graph(g);
  754. X    }
  755. X    else
  756. X        message(g, "No rectangle to zoom into", (char *)NULL);
  757. X}
  758. X
  759. X/* Calculate new limits for ax a for a zoom factor of mult */
  760. Xstatic void zoom_ax(struct ax *a, double mult)
  761. X{
  762. X    if (a->log)
  763. X    {
  764. X        /* Zoom on a log scale ... Real fun with this one :-) */
  765. X        double centre = sqrt(a->min * a->max);
  766. X        double delta = pow(centre, 1.0 - mult);
  767. X
  768. X        a->min = pow(a->min, mult) * delta;
  769. X        a->max = pow(a->max, mult) * delta;
  770. X    }
  771. X    else
  772. X    {
  773. X        /* ax becomes mult times longer, with same centre */
  774. X        double centre = (a->min + a->max) / 2;
  775. X        double delta = centre - a->min;
  776. X
  777. X        a->min = centre - mult * delta;
  778. X        a->max = centre + mult * delta;
  779. X    }
  780. X}
  781. X
  782. X/* Zoom out by a factor factor */
  783. Xvoid zoom_factor(struct graph *g, double factor)
  784. X{
  785. X    if (g->ok)
  786. X    {
  787. X        zoom_ax(&g->a.x, factor);
  788. X        zoom_ax(&g->a.y, factor);
  789. X        check_graph(g);
  790. X    }
  791. X    else
  792. X        message(g, "No scale set !", (char *)NULL);
  793. X}
  794. X
  795. X/* Define new centre for ax */
  796. Xstatic void center_ax(struct ax *a, double centre)
  797. X{
  798. X    if (a->log)
  799. X    {
  800. X        /* more & more fun ... */
  801. X        double delta = sqrt(a->max / a->min);
  802. X
  803. X        a->max = centre * delta;
  804. X        a->min = centre / delta;
  805. X    }
  806. X    else
  807. X    {
  808. X        /* obvious */
  809. X        double delta = (a->max - a->min) / 2.0;
  810. X
  811. X        a->max = centre + delta;
  812. X        a->min = centre - delta;
  813. X    }
  814. X}
  815. X
  816. X/* New centre for graph */
  817. Xvoid center_graph(struct graph *g, double x, double y)
  818. X{
  819. X    if (g->ok && x != NOVAL)
  820. X    {
  821. X        center_ax(&g->a.x, max(min(x, g->a.x.max), g->a.x.min));
  822. X        center_ax(&g->a.y, max(min(y, g->a.y.max), g->a.y.min));
  823. X        check_graph(g);
  824. X    }
  825. X    else
  826. X        message(g, "Nothing to center on", (char *)NULL);
  827. X}
  828. X
  829. X/* Redraw ax a (of graph g), at position xorig on other ax. y_ax is true for
  830. X   drawing of y axis */
  831. Xstatic void draw_ax(struct graph *g, struct ax *a, double xorig, int y_ax)
  832. X{
  833. X    struct TextFont *oldfont, *digits = g->io.digits;
  834. X    struct RWindow *const rwin = g->io.rw;
  835. X    struct RastPort *const rp = rwin->rp;
  836. X    int xtick = yinch2dots(g, XTICK), ytick = xinch2dots(g, YTICK);
  837. X    int xtext = xinch2dots(g, XTEXT), ytext = yinch2dots(g, YTEXT);
  838. X
  839. X    oldfont = rp->Font;
  840. X    SetFont(rp, digits);
  841. X    SetDrMd(rp, JAM1);
  842. X    if (a->ax != NOVAL)
  843. X    {
  844. X        /* Draw ax */
  845. X        if (y_ax)
  846. X        {
  847. X            RMove(rwin, a->ax, a->max);
  848. X            Draw(rwin->rp, rwin->rp->cp_x, ftol(rwin->sy(rwin, a->min)));
  849. X        }
  850. X        else
  851. X        {
  852. X            RMove(rwin, a->max, a->ax);
  853. X            Draw(rwin->rp, ftol(rwin->sx(rwin, a->min)), rwin->rp->cp_y);
  854. X        }
  855. X        if (a->cstep != NOVAL)
  856. X        {
  857. X            /* Draw ticks and numbers */
  858. X            if (a->log)
  859. X            {
  860. X                /* logarithmic ax */
  861. X                double nax;
  862. X                int emin, emax, e, count, i;
  863. X
  864. X                /* Normalise origin (0 < nax < 10). There will be count ticks,
  865. X                   at nax, nax + cstep, nax + 2 * cstep, etc for every exponent
  866. X     
  867. X                   value between min & max */
  868. X                nax = xorig * pow(10.0, -floor(log10(xorig)));
  869. X                /* Exponent range */
  870. X                emin = floor(log10(a->min / nax));
  871. X                emax = ceil(log10(a->max / nax));
  872. X                /* Number of ticks for every exponent value */
  873. X                count = ceil(9 * nax / a->cstep);
  874. X
  875. X                for (e = emin; e <= emax; e++)
  876. X                {
  877. X                    double const p = pow(10.0, (double)e);
  878. X                    double const st = a->cstep * p; /* step between ticks */
  879. X                    double x = p * nax; /* POos. of main tick */
  880. X                    long cx, cy;
  881. X
  882. X                    /* Display main value (at nax, with exponent) */
  883. X                    if (a->every != INOVAL && x != xorig)
  884. X                    {
  885. X                        if (y_ax)
  886. X                            RMove(rwin, a->ax, x);
  887. X                        else
  888. X                            RMove(rwin, x, a->ax);
  889. X
  890. X                        cx = rp->cp_x; cy = rp->cp_y;
  891. X
  892. X                        if (e == 0)
  893. X                        {
  894. X                            /*  don't display 10^0 */
  895. X                            char nb[NBLEN];
  896. X                            int l;
  897. X
  898. X                            /* Display nax */
  899. X                            double2str(nb, nax);
  900. X                            l = strlen(nb);
  901. X                            if (y_ax)
  902. X                                Move(rp, cx + xtext, cy + digits->tf_Baseline /
  903. X 2);
  904. X                            else
  905. X                                Move(rp, cx - digits->tf_XSize * l / 2, cy + di
  906. Xgits->tf_Baseline + ytext);
  907. X                            Text(rp, nb, l);
  908. X                        }
  909. X                        else
  910. X                        {
  911. X                            char nb[NBLEN + 3], expo[NBLEN];
  912. X                            int l1, l2;
  913. X
  914. X                            if (nax == 1)
  915. X                                strcpy(nb, "10");
  916. X                            else
  917. X                            {
  918. X                                double2str(nb, nax);
  919. X                                strcat(nb, "*10");
  920. X                            }
  921. X                            sprintf(expo, "%d", e);
  922. X                            l1 = strlen(nb);
  923. X                            l2 = strlen(expo);
  924. X                            /* Display base */
  925. X                            if (y_ax)
  926. X                                Move(rp, cx + xtext, cy + digits->tf_Baseline /
  927. X 2);
  928. X                            else
  929. X                                Move(rp, cx, cy + digits->tf_Baseline + digits-
  930. X>tf_Baseline / 2 + ytext);
  931. X                            Text(rp, nb, l1);
  932. X                            /* Display exponent */
  933. X                            Move(rp, rp->cp_x, rp->cp_y - digits->tf_Baseline /
  934. X 2);
  935. X                            Text(rp, expo, l2);
  936. X
  937. X                        }
  938. X                    }
  939. X                    /* Now for the ticks ... */
  940. X                    for (i = 0; i < count; i++, x += st)
  941. X                    {
  942. X                        /* Draw tick */
  943. X                        if (y_ax)
  944. X                            RMove(rwin, a->ax, x);
  945. X                        else
  946. X                            RMove(rwin, x, a->ax);
  947. X
  948. X                        cx = rp->cp_x; cy = rp->cp_y;
  949. X
  950. X                        if (y_ax)
  951. X                        {
  952. X                            Move(rp, cx + ytick, cy);
  953. X                            Draw(rp, cx - ytick, cy);
  954. X                        }
  955. X                        else
  956. X                        {
  957. X                            Move(rp, cx, cy + xtick);
  958. X                            Draw(rp, cx, cy - xtick);
  959. X                        }
  960. X                        /* Display digits */
  961. X                        if (i != 0 && a->every != INOVAL && (i % a->every) == 0
  962. X)
  963. X                        {
  964. X                            char nb[NBLEN];
  965. X                            int l;
  966. X
  967. X                            /* Only display mantissa */
  968. X                            double2str(nb, nax + i * a->cstep);
  969. X                            l = strlen(nb);
  970. X                            if (y_ax)
  971. X                                Move(rp, cx + xtext, cy + digits->tf_Baseline /
  972. X 2);
  973. X                            else
  974. X                                Move(rp, cx - digits->tf_XSize * l / 2 + 1, cy
  975. X+ digits->tf_Baseline + ytext);
  976. X                            Text(rp, nb, l);
  977. X                        }
  978. X                    }
  979. X                }
  980. X            }
  981. X            else
  982. X            {
  983. X                /* linear ax */
  984. X                long count, disp_digits;
  985. X                double x;
  986. X
  987. X                /* Number of ticks */
  988. X                count = ceil((a->min - xorig) / a->cstep);
  989. X                /* First tick at which to show value */
  990. X                disp_digits = a->every == INOVAL ?
  991. X                                count - 1 : /* No digits displayed */
  992. X                                a->every * (long)ceil((a->min - xorig) / (a->cs
  993. Xtep * a->every));
  994. X
  995. X                for(x = count * a->cstep + xorig; x <= a->max; x += a->cstep, c
  996. Xount++)
  997. X                {
  998. X                    long cx, cy;
  999. X
  1000. X                    /* Draw tick */
  1001. X                    if (y_ax)
  1002. X                        RMove(rwin, a->ax, x);
  1003. X                    else
  1004. X                        RMove(rwin, x, a->ax);
  1005. X
  1006. X                    cx = rp->cp_x; cy = rp->cp_y;
  1007. X
  1008. X                    if (y_ax)
  1009. X                    {
  1010. X                        Move(rp, cx + ytick, cy);
  1011. X                        Draw(rp, cx - ytick, cy);
  1012. X                    }
  1013. X                    else
  1014. X                    {
  1015. X                        Move(rp, cx, cy + xtick);
  1016. X                        Draw(rp, cx, cy - xtick);
  1017. X                    }
  1018. X
  1019. X                    /* Display digits */
  1020. X                    if (count == disp_digits)
  1021. X                    {
  1022. X                        char nb[NBLEN];
  1023. X                        int l;
  1024. X
  1025. X                        /* Next one in every ticks */
  1026. X                        disp_digits += a->every;
  1027. X
  1028. X                        if (count != 0) /* Not at origin */
  1029. X                        {
  1030. X                            double2str(nb, x);
  1031. X                            l = strlen(nb);
  1032. X                            if (y_ax)
  1033. X                                Move(rp, cx + xtext, cy + digits->tf_Baseline /
  1034. X 2);
  1035. X                            else
  1036. X                                Move(rp, cx - digits->tf_XSize * l / 2, cy + di
  1037. Xgits->tf_Baseline + ytext);
  1038. X                            Text(rp, nb, l);
  1039. X                        }
  1040. X                    }
  1041. X                }
  1042. X            }
  1043. X        }
  1044. X    }
  1045. X    SetFont(rp, oldfont);
  1046. X}
  1047. X
  1048. X/* Draws directly into the rastport, used internally. allow_mes nust be FALSE
  1049. X   if called during window refresh */
  1050. Xstatic void do_draw(struct graph *g, int allow_mes)
  1051. X{
  1052. X    struct object *o;
  1053. X
  1054. X    if (g->ok && g->io.rw)
  1055. X    {
  1056. X        /* Draw axes */
  1057. X        SetAPen(g->io.rw->rp, 1L);
  1058. X        if (g->a.ok)
  1059. X        {
  1060. X            draw_ax(g, &g->a.x, g->a.y.ax, FALSE);
  1061. X            draw_ax(g, &g->a.y, g->a.x.ax, TRUE);
  1062. X        }
  1063. X
  1064. X        /* Draw objects */
  1065. X        for (o = first(&g->o_list); succ(o); o = succ(o))
  1066. X            if (o != g->s.current && o->ok) o->draw(o, allow_mes);
  1067. X
  1068. X        /* Current object is always last so that it appears "on top" */
  1069. X        if (g->s.current && g->s.current->ok) g->s.current->draw(g->s.current,
  1070. Xallow_mes);
  1071. X    }
  1072. X}
  1073. X
  1074. X/* Redraw graph completely */
  1075. Xvoid draw_graph(struct graph *g, int allow_mes)
  1076. X{
  1077. X    if (allow_mes) set_title(g);
  1078. X
  1079. X    SetRast(g->io.rw->rp, 0); /* Clear window */
  1080. X
  1081. X    do_draw(g, allow_mes);
  1082. X}
  1083. X
  1084. X/* Redraw graph partially (ref is NULL for no redraw). ref is disposed when
  1085. X   refresh is done */
  1086. Xvoid refresh_graph(struct graph *g, int allow_mes, struct Region *ref)
  1087. X{
  1088. X    if (ref)
  1089. X    {
  1090. X        if (g->io.rw)
  1091. X        {
  1092. X            /* Setup clipping */
  1093. X            struct Region *oldRegion = InstallClipRegion(g->io.rw->rp->Layer, r
  1094. Xef);
  1095. X
  1096. X            SetRast(g->io.rw->rp, 0);
  1097. X            do_draw(g, allow_mes);
  1098. X
  1099. X            InstallClipRegion(g->io.rw->rp->Layer, oldRegion);
  1100. X        }
  1101. X        DisposeRegion(ref);
  1102. X    }
  1103. X}
  1104. X
  1105. X/* Returns a region that will fully refresh g.
  1106. X   (makes a copy of the current region) */
  1107. Xstruct Region *full_refresh(struct graph *g)
  1108. X{
  1109. X    struct Region *r;
  1110. X
  1111. X    if ((r = NewRegion()) && g->io.rw)
  1112. X    {
  1113. X        struct Region *old = InstallClipRegion(g->io.rw->rp->Layer, NULL);
  1114. X
  1115. X        /* Make copy */
  1116. X        if (!OrRegionRegion(old, r))
  1117. X        {
  1118. X            DisposeRegion(r);
  1119. X            r = NULL;
  1120. X        }
  1121. X
  1122. X        InstallClipRegion(g->io.rw->rp->Layer, old);
  1123. X    }
  1124. X    return r;
  1125. X}
  1126. X
  1127. X/* Open printer.device */
  1128. Xstatic int open_prt(void)
  1129. X{
  1130. X    if (prtport = CreatePort(0L, 0L))
  1131. X    {
  1132. X        if (prtio = (struct IODRPReq *)CreateExtIO(prtport, sizeof(struct IODRP
  1133. XReq)))
  1134. X        {
  1135. X            if (OpenDevice("printer.device", 0, (struct IORequest *)prtio, 0) =
  1136. X= 0)
  1137. X            {
  1138. X                ped = &((struct PrinterData *)prtio->io_Device)->pd_SegmentData
  1139. X->ps_PED;
  1140. X                prtprefs = &((struct PrinterData *)prtio->io_Device)->pd_Prefer
  1141. Xences;
  1142. X
  1143. X                return TRUE;
  1144. X            }
  1145. X            DeleteExtIO((struct IORequest *)prtport);
  1146. X        }
  1147. X        DeletePort(prtport);
  1148. X    }
  1149. X    return FALSE;
  1150. X}
  1151. X
  1152. X/* Close printer device */
  1153. Xstatic void close_prt(void)
  1154. X{
  1155. X    CloseDevice((struct IORequest *)prtio);
  1156. X    DeleteExtIO((struct IORequest *)prtio);
  1157. X    DeletePort(prtport);
  1158. X}
  1159. X
  1160. X/* Easy access to DumpRPort. wait : DoIO or SendIO ? */
  1161. Xstatic void prt_raster(int wait, struct RastPort *rp, struct ColorMap *cm, ULON
  1162. XG m, UWORD sx, UWORD sy, UWORD w, UWORD h, LONG dc, LONG dr, UWORD special)
  1163. X{
  1164. X    prtio->io_RastPort = rp;
  1165. X    prtio->io_ColorMap = cm;
  1166. X    prtio->io_Modes = m;
  1167. X    prtio->io_SrcX = sx;
  1168. X    prtio->io_SrcY = sy;
  1169. X    prtio->io_SrcWidth = w;
  1170. X    prtio->io_SrcHeight = h;
  1171. X    prtio->io_DestCols = dc;
  1172. X    prtio->io_DestRows = dr;
  1173. X    prtio->io_Special = special;
  1174. X    prtio->io_Command = PRD_DUMPRPORT;
  1175. X    if (wait) DoIO(prtio);
  1176. X    else SendIO(prtio);
  1177. X}
  1178. X
  1179. X/* Print a slice of the dump to the printer */
  1180. Xstatic int prt_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
  1181. X int slice, struct Requester *abreq)
  1182. X{
  1183. X    struct RWindow *old = g->io.rw;
  1184. X    int ret = FALSE;
  1185. X    ULONG prtsig = 1 << prtio->io_Message.mn_ReplyPort->mp_SigBit;
  1186. X    ULONG winsig = 1 << g->io.win->UserPort->mp_SigBit;
  1187. X
  1188. X    /* Create coords for slice */
  1189. X    g->io.rw = new_RWindow(rp, w, slice,
  1190. X                           0, y + slice - h, 0, -y,
  1191. X                           g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
  1192. X                           g->a.x.log, g->a.y.log, FALSE);
  1193. X    if (g->io.rw)
  1194. X    {
  1195. X        int done = FALSE;
  1196. X
  1197. X        /* Draw into rastport. Note that it may be > 1024 x 1024 ! */
  1198. X        BigSetRast(rp, 0);
  1199. X        do_draw(g, TRUE);
  1200. X        prt_raster(FALSE, rp, prtcm, 0L, 0, 0, (UWORD)w, (UWORD)slice, w, slice
  1201. X, SPECIAL_NOFORMFEED);
  1202. X
  1203. X        do { /* Wait for end of printing or abort */
  1204. X            Wait(prtsig | winsig);
  1205. X            if (aborted(abreq))
  1206. X            {
  1207. X                done = TRUE;
  1208. X                ret = FALSE; /* Stop! */
  1209. X                if (!CheckIO(prtio))
  1210. X                {
  1211. X                    AbortIO(prtio);
  1212. X                    WaitIO(prtio);
  1213. X                }
  1214. X                prtio->io_Error = 0;
  1215. X            }
  1216. X            else if (CheckIO(prtio))
  1217. X            {
  1218. X                done = TRUE;
  1219. X                ret = prtio->io_Error == 0;
  1220. X            }
  1221. X        } while (!done);
  1222. X        g->io.rw->delete(g->io.rw);
  1223. X    }
  1224. X    else
  1225. X        nomem(g->io.win);
  1226. X    g->io.rw = old;
  1227. X    return ret;
  1228. X}
  1229. X
  1230. X/* Work out the max size for a slice (don't use more than half the largest
  1231. X   chunk of chip ram). The height must be a multiple of quanta */
  1232. Xstatic int get_slice_height(int w, int h, int quanta)
  1233. X{
  1234. X    long use = AvailMem(MEMF_CHIP | MEMF_LARGEST) / 2;
  1235. X    long min = 2 * RASSIZE(w, quanta);
  1236. X    long nb = use / min;
  1237. X
  1238. X    if (nb == 0) /* Not much mem ... */ return quanta;
  1239. X    else if (nb * quanta > h) return h;
  1240. X    else return nb * quanta;
  1241. X}
  1242. X
  1243. X/* Create a 2 plane Rastport with clipping at its limits (-> Layer)  */
  1244. Xstatic struct RastPort *alloc_ras(int w, int h)
  1245. X{
  1246. X    struct Layer_Info *li;
  1247. X    struct BitMap *bm;
  1248. X    BYTE *data;
  1249. X    struct Layer *l;
  1250. X
  1251. X    /* Alloc components */
  1252. X    if (li = NewLayerInfo())
  1253. X    {
  1254. X        if (bm = AllocMem(sizeof(struct BitMap), 0L))
  1255. X        {
  1256. X            if (data = AllocMem(2 * RASSIZE(w, h), MEMF_CHIP))
  1257. X            {
  1258. X                /* Set up data structure */
  1259. X                InitBitMap(bm, 2, w, h);
  1260. X                bm->Planes[0] = (PLANEPTR)data;
  1261. X                bm->Planes[1] = (PLANEPTR)(data + RASSIZE(w, h));
  1262. X
  1263. X                if (l = CreateUpfrontLayer(li, bm, 0, 0, w - 1, h - 1, LAYERSIM
  1264. XPLE, NULL))
  1265. X                    return l->rp;
  1266. X
  1267. X                FreeMem(data, 2 * RASSIZE(w, h));
  1268. X            }
  1269. X            FreeMem(bm, sizeof(struct BitMap));
  1270. X        }
  1271. X        DisposeLayerInfo(li);
  1272. X    }
  1273. X    return NULL;
  1274. X}
  1275. X
  1276. X/* Free rastport created by alloc_ras */
  1277. Xstatic void free_ras(struct RastPort *rp)
  1278. X{
  1279. X    struct Layer_Info *li = rp->Layer->LayerInfo;
  1280. X    struct BitMap *bm = rp->BitMap;
  1281. X
  1282. X    DeleteLayer(li, rp->Layer);
  1283. X    FreeMem(bm->Planes[0], bm->BytesPerRow * bm->Rows * bm->Depth);
  1284. X    FreeMem(bm, sizeof(struct BitMap));
  1285. X    DisposeLayerInfo(li);
  1286. X}
  1287. X
  1288. X/* Print graph into a bitmap which is w by h pixels, resolution xdpm, ydpm,
  1289. X   quanta is the size of the print head (if any, 1 otherwise). dump_slice is
  1290. X   called for every slice.
  1291. X   Rem: printing is broken into horizontal slices, according to available
  1292. X   memory */
  1293. Xstatic void prt(struct graph *g, int w, int h, int quanta, int xdpm, int ydpm,
  1294. Xprtfunc dump_slice)
  1295. X{
  1296. X    int slice, y, ok = TRUE;
  1297. X    struct RastPort *rp;
  1298. X    struct Requester *abreq;
  1299. X    struct Requester *req;
  1300. X    struct Memory *m;
  1301. X    struct Gadget *gl = NULL, *thin;
  1302. X    char size[NBLEN];
  1303. X
  1304. X    size[0] = '\0';
  1305. X
  1306. X    /* Ask user for print characteristics (pen size) */
  1307. X    if ((m = NewMemory()) &&
  1308. X        (req = InitReq(50, 20, 180, 85, m)) &&
  1309. X        SetReqBorder(req, 1, m) &&
  1310. X        AddIntuiText(&req->ReqText, "Print Characteristics", 6, 6, m) &&
  1311. X        (thin = AddRadio(&gl, 0, "Thin", TRUE, SELECTED, RELVERIFY, 2, 11, 20,
  1312. X10, 10, m)) &&
  1313. X        AddRadio(&gl, 0, "Thick,", TRUE, 0, RELVERIFY, 1, 11, 40, 10, 10, m) &&
  1314. X     
  1315. X        AddText(&gl, 0, "Size ", FALSE, size, NBLEN, TRUE, 0, RELVERIFY, 128, 4
  1316. X1, 32, 10, TRUE, m) &&
  1317. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 13, 60, 65, 15, FALSE
  1318. X, m) &&
  1319. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 103, 60, 65, 15,
  1320. X FALSE, m))
  1321. X    {
  1322. X        SetReqGadgets(req, gl);
  1323. X        if (DoRequest(req, g, std_ghandler))
  1324. X        {
  1325. X            double ptsize = str2double(size);
  1326. X
  1327. X            if ((thin->Flags & SELECTED) || (ptsize > 0.0 && ptsize != NOVAL))
  1328. X            {
  1329. X                /* Set up for printing */
  1330. X                if (set_dpm(g, xdpm, ydpm))
  1331. X                {
  1332. X                    slice = get_slice_height(w, h, quanta);
  1333. X                    if (rp = alloc_ras(w, slice))
  1334. X                    {
  1335. X                        if (abreq = abort_request(g, "Printing, slice
  1336. X "))
  1337. X                        {
  1338. X                            if (thin->Flags & SELECTED) set_thin(g, rp);
  1339. X                            else set_pensize(g, rp, ptsize);
  1340. X
  1341. X                            /* Print all the slices */
  1342. X                            for (y = 0; ok && y < h; y += slice)
  1343. X                            {
  1344. X                                char msg[30];
  1345. X
  1346. X                                sprintf(msg, "Printing, slice %d of %d", y / sl
  1347. Xice + 1, (h + slice - 1) / slice);
  1348. X                                set_abort_msg(abreq, msg);
  1349. X                                ok = dump_slice(g, rp, w, h, y, min(slice, h -
  1350. Xy), abreq);
  1351. X                            }
  1352. X                            end_abort_request(abreq);
  1353. X                        }
  1354. X                        else
  1355. X                            message(g, "Abort requester failed", (char *)NULL);
  1356. X     
  1357. X                        free_ras(rp);
  1358. X                    }
  1359. X                    else
  1360. X                        nomem(g->io.win);
  1361. X                    /* Return to screen */
  1362. X                    set_dpm(g, scr_dpmx, scr_dpmy);
  1363. X                }
  1364. X            }
  1365. X            else
  1366. X                message(g, "Illegal line size", (char *)NULL);
  1367. X        }
  1368. X    }
  1369. X    Free(m);
  1370. X}
  1371. X
  1372. X/* get max size of printed output */
  1373. Xstatic int get_max_size(struct graph *g, int *w, int *h, int *quanta)
  1374. X{
  1375. X    prt_raster(TRUE, g->io.win->RPort, prtcm, 0L, 0, 0, g->io.win->Width, g->io
  1376. X.win->Height, LONG_MAX, LONG_MAX, SPECIAL_NOPRINT);
  1377. X
  1378. X    *w = prtio->io_DestCols;
  1379. X    *h = prtio->io_DestRows;
  1380. X    /* If length = infinity, use MAXPRINTPAGES pages */
  1381. X    if (*h == LONG_MAX)
  1382. X        *h = (ped->ped_YDotsInch * MAXPRINTPAGES * prtprefs->PaperLength) / (pr
  1383. Xtprefs->PrintSpacing == SIX_LPI ? 6 : 8);
  1384. X    *quanta = ped->ped_NumRows;
  1385. X
  1386. X    return prtio->io_Error == 0;
  1387. X}
  1388. X
  1389. X/* Determine size which fits asked for ratio (when no absolute size set in
  1390. X   preferences) */
  1391. Xstatic int get_size(struct graph *g, int *w, int *h, int *quanta)
  1392. X{
  1393. X    if (get_max_size(g, w, h, quanta))
  1394. X    {
  1395. X        if (g->ok && g->a.ok && g->a.ratio != NOVAL)
  1396. X        {
  1397. X            /* adjust for ratio */
  1398. X            double r = g->a.ratio /
  1399. X                fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
  1400. X.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
  1401. X                     (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
  1402. X.x.max - g->a.x.min)) * ped->ped_YDotsInch));
  1403. X
  1404. X            if (r > 1.0) /* make X smaller */
  1405. X                *w /= r;
  1406. X            else /* make Y smaller */
  1407. X                *h *= r;
  1408. X        }
  1409. X        if (*w == 0) *w = 1;
  1410. X        if (*h == 0) *h = 1;
  1411. X        return TRUE;
  1412. X    }
  1413. X    return FALSE;
  1414. X}
  1415. X
  1416. X/* determine size to use when user has set abs. size in preferences */
  1417. Xstatic int get_abs_size(struct graph *g, int *w, int *h, int *quanta)
  1418. X{
  1419. X    if (get_max_size(g, w, h, quanta))
  1420. X    {
  1421. X        if (g->ok && g->a.ok && g->a.ratio != NOVAL)
  1422. X        {
  1423. X            /* Adjust only if dimension is free (size set to 0) */
  1424. X            double r = g->a.ratio /
  1425. X                fabs((*h / (g->a.y.log ? log10(g->a.y.max / g->a.y.min) : (g->a
  1426. X.y.max - g->a.y.min)) * ped->ped_XDotsInch) /
  1427. X                     (*w / (g->a.x.log ? log10(g->a.x.max / g->a.x.min) : (g->a
  1428. X.x.max - g->a.x.min)) * ped->ped_YDotsInch));
  1429. X
  1430. X            if (r > 1.0 && prtprefs->PrintMaxWidth == 0) /* make X smaller */
  1431. X                *w /= r;
  1432. X            else if (r < 1.0 && prtprefs->PrintMaxHeight == 0) /* make Y smalle
  1433. Xr */
  1434. X                *h *= r;
  1435. X        }
  1436. X        if (*w == 0) *w = 1;
  1437. X        if (*h == 0) *h = 1;
  1438. X        return TRUE;
  1439. X    }
  1440. X    return FALSE;
  1441. X}
  1442. X
  1443. X/* Print a graph */
  1444. Xvoid prt_graph(struct graph *g)
  1445. X{
  1446. X    int w, h, quanta;
  1447. X
  1448. X    if (g->ok)
  1449. X        if (open_prt())
  1450. X        {
  1451. X            prtprefs->PrintFlags &= ~INTEGER_SCALING; /* We produce nice output
  1452. X anyway ! */
  1453. X            prtprefs->PrintAspect = ASPECT_HORIZ; /* No support for vertical pl
  1454. Xots */
  1455. X
  1456. X            switch (prtprefs->PrintFlags & DIMENSIONS_MASK)
  1457. X            {
  1458. X                case MULTIPLY_DIMENSIONS: /* Ignored */
  1459. X                    prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
  1460. X                    /* FALLTHROUGH */
  1461. X                case IGNORE_DIMENSIONS:
  1462. X                case BOUNDED_DIMENSIONS:
  1463. X                    if (get_size(g, &w, &h, &quanta))
  1464. X                    {
  1465. X                        prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
  1466. X                        prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
  1467. X(int)(ped->ped_YDotsInch / INCH), prt_slice);
  1468. X                    }
  1469. X                    break;
  1470. X
  1471. X                case ABSOLUTE_DIMENSIONS:
  1472. X                case PIXEL_DIMENSIONS:
  1473. X                    if (get_abs_size(g, &w, &h, &quanta))
  1474. X                    {
  1475. X                        prtprefs->PrintFlags &= ~DIMENSIONS_MASK;
  1476. X                        prt(g, w, h, quanta, (int)(ped->ped_XDotsInch / INCH),
  1477. X(int)(ped->ped_YDotsInch / INCH), prt_slice);
  1478. X                    }
  1479. X                    break;
  1480. X            }
  1481. X            if (prtio->io_Error > 0) /* Printer error */
  1482. X                message(g, "Printer Error", prt_error[prtio->io_Error > MAX_PRT
  1483. X_ERROR ? 0 : prtio->io_Error], (char *)NULL);
  1484. X            close_prt();
  1485. X        }
  1486. X        else
  1487. X            message(g, "Couldn't open printer\n", (char *)NULL);
  1488. X}
  1489. X
  1490. X/* Write slice into body. Must add byteRun1 compression */
  1491. Xstatic int write_iffslice(struct BitMap *bm)
  1492. X{
  1493. X    int y, plane;
  1494. X
  1495. X    for (y = 0; y < bm->Rows; y++)
  1496. X    {
  1497. X        /* Interleave bit planes */
  1498. X        for (plane = 0; plane < bm->Depth; plane++)
  1499. X            if (!fwrite(bm->Planes[plane] + y * bm->BytesPerRow, bm->BytesPerRo
  1500. Xw, 1, iff_file))
  1501. X                return FALSE;
  1502. X    }
  1503. X    return TRUE;
  1504. X}
  1505. X
  1506. X/* Draw & write into slice for iff output */
  1507. Xstatic int iff_slice(struct graph *g, struct RastPort *rp, int w, int h, int y,
  1508. X int slice, struct Requester *abreq)
  1509. X{
  1510. X    struct RWindow *old = g->io.rw;
  1511. X    int ret = FALSE;
  1512. X
  1513. X    g->io.rw = new_RWindow(rp, w, slice,
  1514. X                           0, y + slice - h, 0, -y,
  1515. X                           g->a.x.min, g->a.y.min, g->a.x.max, g->a.y.max,
  1516. X                           g->a.x.log, g->a.y.log, FALSE);
  1517. X    if (g->io.rw)
  1518. X    {
  1519. X        BigSetRast(rp, 0);
  1520. X        do_draw(g, TRUE);
  1521. X        if (write_iffslice(rp->BitMap))
  1522. X        {
  1523. X            if (!aborted(abreq)) ret = TRUE;
  1524. X        }
  1525. X        else
  1526. X            message(g, "Error writing file", (char *)NULL);
  1527. X
  1528. X        g->io.rw->delete(g->io.rw);
  1529. X    }
  1530. X    else
  1531. X        nomem(g->io.win);
  1532. X    g->io.rw = old;
  1533. X    return ret;
  1534. X}
  1535. X
  1536. X/* Write ILBM header to file (BMHD, CMAP & start of BODY). Save positions for
  1537. X   writing sizes */
  1538. Xstatic int start_iff(char *name, int w, int h, int xdpi, int ydpi)
  1539. X{
  1540. X    if (iff_file = fopen(name, "w"))
  1541. X    {
  1542. X        if (fwrite("FORM", 4, 1, iff_file) && (form_pos = ftell(iff_file)) != -
  1543. X1L &&
  1544. X            fwrite("\0\0\0\0ILBMBMHD\0\0\0\024", 16, 1, iff_file))
  1545. X        {
  1546. X            static BitMapHeader bm = {
  1547. X                0, 0, 0, 0, 2, mskNone, cmpNone, 0, 0
  1548. X            };
  1549. X            bm.w = w; bm.h = h;
  1550. X            bm.xAspect = ydpi; bm.yAspect = xdpi;
  1551. X            bm.pageWidth = w; bm.pageHeight = h;
  1552. X
  1553. X            if (fwrite((char *)&bm, sizeof(bm), 1, iff_file) &&
  1554. X                fwrite("CMAP\0\0\0\14", 8, 1, iff_file) &&
  1555. X                fwrite("\xff\xff\xff\0\0\0\0\0\0\0\0\0", 12, 1, iff_file) &&
  1556. X                fwrite("BODY", 4, 1, iff_file) && (body_pos = ftell(iff_file))
  1557. X!= -1 &&
  1558. X                fwrite("\0\0\0\0", 4, 1, iff_file))
  1559. X            {
  1560. X                return TRUE;
  1561. X            }
  1562. X        }
  1563. X        /* If failed, delete file */
  1564. X        if (fclose(iff_file) == 0) unlink(name);
  1565. X    }
  1566. X    return FALSE;
  1567. X}
  1568. X
  1569. X/* Write end of iff_file, ie pad, write lengths & close */
  1570. Xstatic int end_iff(void)
  1571. X{
  1572. X    long end = ftell(iff_file), end2 = end;
  1573. X
  1574. X    if (end != -1)
  1575. X    {
  1576. X        if ((end & 1) == 0 || (end2++, fwrite("\0", 1, 1, iff_file))) /* pad. y
  1577. Xuck. */
  1578. X        {
  1579. X            long formlen = end2 - form_pos - 4; /* Includes pad byte */
  1580. X            long bodylen = end - body_pos - 4;  /* Doesn't */
  1581. X
  1582. X            if (fseek(iff_file, form_pos, 0) != -1 &&
  1583. X                fwrite((char *)&formlen, sizeof(long), 1, iff_file) &&
  1584. X                fseek(iff_file, body_pos, 0) != -1 &&
  1585. X                fwrite((char *)&bodylen, sizeof(long), 1, iff_file))
  1586. X            {
  1587. X                return fclose(iff_file) == 0;
  1588. X            }
  1589. X        }
  1590. X    }
  1591. X    return FALSE;
  1592. X}
  1593. X
  1594. X/* Handle iff requester: display file req when user clicks on disk */
  1595. Xstatic int iff_handler(struct Gadget *gg, ULONG class, struct Requester *req, s
  1596. Xtruct graph *g)
  1597. X{
  1598. X    if (gg->GadgetID == IFFDISK)
  1599. X    {
  1600. X        char file[FILELEN];
  1601. X
  1602. X        if (getfile(file, "IFF Output file"))
  1603. X        {
  1604. X            UWORD pos = RemoveGList(req->RWindow, iffg, 1);
  1605. X            strcpy(iff_filename, file);
  1606. X            RefreshGList(iffg, req->RWindow, req, 1);
  1607. X            AddGList(req->RWindow, iffg, pos, 1, req);
  1608. X        }
  1609. X        ActivateGadget(iffg, req->RWindow, req);
  1610. X        return FALSE;
  1611. X    }
  1612. X    else return std_ghandler(gg, class, req, g);
  1613. X}
  1614. X
  1615. X/* Output graph as ILBM. Asks for bitmap size, and resolution. Ignores graph
  1616. X   ratio. */
  1617. Xvoid iff_todisk(struct graph *g)
  1618. X{
  1619. X    struct Requester *req;
  1620. X    struct Memory *m;
  1621. X    struct Gadget *gl = NULL;
  1622. X    char xsize[NBLEN], ysize[NBLEN], xdpi[NBLEN], ydpi[NBLEN];
  1623. X
  1624. X    xsize[0] = '\0'; ysize[0] = '\0';
  1625. X    strcpy(xdpi, "72"); strcpy(ydpi, "72");
  1626. X
  1627. X    iff_filename[0] = '\0';
  1628. X    if ((m = NewMemory()) &&
  1629. X        (req = InitReq(50, 20, 280, 110, m)) &&
  1630. X        SetReqBorder(req, 1, m) &&
  1631. X        AddIntuiText(&req->ReqText, "Write IFF", 104, 6, m) &&
  1632. X        (iffg = AddText(&gl, 0, "File ", FALSE, iff_filename, FILELEN, TRUE, 0,
  1633. X RELVERIFY, 51, 20, 144, 10, TRUE, m)) &&
  1634. X        AddBox(&gl, IFFDISK, "Disk", 0, RELVERIFY, 205, 17, 65, 15, FALSE, m) &
  1635. X&
  1636. X        AddText(&gl, 0, "Size: X ", FALSE, xsize, INTLEN, TRUE, 0, RELVERIFY, 7
  1637. X5, 45, 32, 10, TRUE, m) &&
  1638. X        AddText(&gl, 0, "Y ", FALSE, ysize, INTLEN, TRUE, 0, RELVERIFY, 140, 45
  1639. X, 32, 10, TRUE, m) &&
  1640. X        AddText(&gl, 0, "DPI: X ", FALSE, xdpi, INTLEN, TRUE, 0, RELVERIFY, 83,
  1641. X 65, 32, 10, TRUE, m) &&
  1642. X        AddText(&gl, 0, "Y ", FALSE, ydpi, INTLEN, TRUE, 0, RELVERIFY, 140, 65,
  1643. X 32, 10, TRUE, m) &&
  1644. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 38, 85, 65, 15, FALSE
  1645. X, m) &&
  1646. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 178, 85, 65, 15,
  1647. X FALSE, m))
  1648. X    {
  1649. X        SetReqGadgets(req, gl);
  1650. X        if (DoRequest(req, g, iff_handler))
  1651. X        {
  1652. X            int w = str2int(xsize);
  1653. X            int h = str2int(ysize);
  1654. X            int xdp = str2int(xdpi);
  1655. X            int ydp = str2int(ydpi);
  1656. X
  1657. X            if (w > 0 && h > 0 && xdp > 0 && ydp > 0 &&
  1658. X                w != NOVAL && h != NOVAL && xdp != NOVAL && ydp != NOVAL)
  1659. X                if (start_iff(iff_filename, w, h, xdp, ydp))
  1660. X                {
  1661. X                    prt(g, w, h, 1, (int)(xdp / INCH), (int)(ydp / INCH), iff_s
  1662. Xlice);
  1663. X                    if (!end_iff())
  1664. X                        message(g, "Error writing file", (char *)NULL);
  1665. X                }
  1666. X                else
  1667. X                    message(g, "Error writing file", (char *)NULL);
  1668. X            else
  1669. X                message(g, "Illegal dimensions !", (char *)NULL);
  1670. X        }
  1671. X    }
  1672. X    Free(m);
  1673. X}
  1674. X
  1675. X/* Write graph to file f */
  1676. Xint save_graph(struct graph *g, FILE *f)
  1677. X{
  1678. X    int ok = FALSE;
  1679. X    short tag = GRAPH_TAG;
  1680. X
  1681. X    /* Write graph information */
  1682. X    if (WRITE(f, tag) &&
  1683. X        WRITE(f, g->io.win->LeftEdge) &&
  1684. X        WRITE(f, g->io.win->TopEdge) &&
  1685. X        WRITE(f, g->io.win->Width) &&
  1686. X        WRITE(f, g->io.win->Height) &&
  1687. X        WRITE(f, g->name) &&
  1688. X        WRITE(f, g->a))
  1689. X    {
  1690. X        struct object *scan;
  1691. X
  1692. X        ok = TRUE;
  1693. X        /* Write all objects */
  1694. X        for (scan = first(&g->o_list); ok && succ(scan); scan = succ(scan))
  1695. X        {
  1696. X            if (!scan->save(scan, f)) ok = FALSE;
  1697. X        }
  1698. X        /* Write end tag */
  1699. X        if (ok)
  1700. X        {
  1701. X            tag = GRAPH_END;
  1702. X            ok = WRITE(f, tag);
  1703. X            g->saved = TRUE;
  1704. X        }
  1705. X    }
  1706. X    return ok;
  1707. X}
  1708. X
  1709. X/* Load & create new graph from file f (graph tag already read) */
  1710. Xstruct graph *load_graph(struct graph *from, FILE *f)
  1711. X{
  1712. X    struct graph *g = new_graph(from);
  1713. X
  1714. X    if (g)
  1715. X    {
  1716. X        WORD leftedge, topedge, width, height;
  1717. X        int ok = FALSE;
  1718. X
  1719. X        /* Read graph info */
  1720. X        if (READ(f, leftedge) &&
  1721. X            READ(f, topedge) &&
  1722. X            READ(f, width) &&
  1723. X            READ(f, height) &&
  1724. X            READ(f, g->name) &&
  1725. X            READ(f, g->a))
  1726. X        {
  1727. X            int done = FALSE;
  1728. X
  1729. X            ok = TRUE;
  1730. X            do /* Read objects */
  1731. X            {
  1732. X                short tag;
  1733. X                struct object *o = NULL;
  1734. X
  1735. X                if (READ(f, tag))
  1736. X                    switch (tag) /* We have to know which objects exist ... */
  1737. X                    {
  1738. X                        case GRAPH_END:
  1739. X                            done = TRUE;
  1740. X                            break;
  1741. X                        case LABEL_TAG:
  1742. X                            o = (struct object *)load_label(g, f);
  1743. X                            break;
  1744. X                        case FUNCTION_TAG:
  1745. X                            o = (struct object *)load_function(g, f);
  1746. X                            break;
  1747. X                        default:
  1748. X                            message(g, "File is not a graph", (char *)NULL);
  1749. X                            break;
  1750. X                    }
  1751. X                ok = done || o != NULL;
  1752. X                if (o)
  1753. X                    add_tail(&g->o_list, o);
  1754. X            } while (!done && ok);
  1755. X
  1756. X        }
  1757. X        if (!ok)
  1758. X        {
  1759. X            delete_graph(g);
  1760. X            g = NULL;
  1761. X        }
  1762. X        else /* All ok, display */
  1763. X        {
  1764. X            check_graph(g);
  1765. X            g->saved = TRUE;
  1766. X        }
  1767. X    }
  1768. X    return g;
  1769. X}
  1770. X
  1771. X/* Delete a graph */
  1772. Xvoid delete_graph(struct graph *g)
  1773. X{
  1774. X    struct object *o, *next;
  1775. X
  1776. X    /* Deselect */
  1777. X    if (g->s.current) g->s.current->deselect(g->s.current);
  1778. X
  1779. X    /* Delete all objects */
  1780. X    for (o = first(&g->o_list); next = succ(o); o = next)
  1781. X    {
  1782. X        struct Region *ref = o->delete(o);
  1783. X
  1784. X        DisposeRegion(ref);
  1785. X    }
  1786. X
  1787. X    /* Delete all local resources */
  1788. X    if (g->io.rw) g->io.rw->delete(g->io.rw);
  1789. X    CloseFont(g->io.digits);
  1790. X    cleanup_uio(g); /* Clears menus, closes window ... */
  1791. X    FreeMem(g, sizeof(struct graph));
  1792. X}
  1793. X
  1794. X/* Create a new graph */
  1795. Xstruct graph *new_graph(struct graph *from)
  1796. X{
  1797. X    struct graph *const g = AllocMem(sizeof(struct graph), 0L);
  1798. X    char *msg;
  1799. X    const static struct graph def_g = { /* Default values */
  1800. X        { NULL },
  1801. X        FALSE, TRUE,
  1802. X        "Graph",
  1803. X        { MENUNULL },
  1804. X        { NULL },
  1805. X        {
  1806. X            {
  1807. X                NOVAL, NOVAL,
  1808. X                NOVAL, NOVAL,
  1809. X                INOVAL,
  1810. X                FALSE
  1811. X            },
  1812. X            {
  1813. X                NOVAL, NOVAL,
  1814. X                NOVAL, NOVAL,
  1815. X                INOVAL,
  1816. X                FALSE
  1817. X            },
  1818. X            NOVAL,
  1819. X            FALSE, FALSE
  1820. X        },
  1821. X        {
  1822. X            FALSE, FALSE,
  1823. X            NOVAL, NOVAL,
  1824. X            NULL
  1825. X        }
  1826. X    };
  1827. X
  1828. X    if (g)
  1829. X    {
  1830. X        *g = def_g;
  1831. X        g->io.dpmx = scr_dpmx; g->io.dpmy = scr_dpmy;
  1832. X        new_list(&g->o_list); /* no objects */
  1833. X        if (g->io.digits = open_font(g, "digits.font", DIGHEIGHT, 0, 0))
  1834. X        {
  1835. X            if (init_uio(g)) /* Open window */
  1836. X            {
  1837. X                set_scale(g);
  1838. X                draw_graph(g, TRUE); /* & display */
  1839. X                return g;
  1840. X            }
  1841. X            else msg = "No window";
  1842. X            CloseFont(g->io.digits);
  1843. X        }
  1844. X        else msg = "digits.font missing";
  1845. X        FreeMem(g, sizeof(struct graph));
  1846. X    }
  1847. X    else msg = "No memory !";
  1848. X
  1849. X    message(from, "Couldn't create graph", msg, (char *)NULL);
  1850. X
  1851. X    return NULL;
  1852. X}
  1853. X
  1854. X/* Global initialisation */
  1855. Xint init_grph(void)
  1856. X{
  1857. X    struct Screen wbscr;
  1858. X
  1859. X    /* Find screen resolution */
  1860. X    scr_dpmx = GfxBase->NormalDPMX;
  1861. X    scr_dpmy = GfxBase->NormalDPMY;
  1862. X    if (!GetScreenData((char *)&wbscr, sizeof(struct Screen), WBENCHSCREEN, NUL
  1863. XL))
  1864. X        return alert(NULL, "No Workbench !", NULL), FALSE;
  1865. X
  1866. X    if (wbscr.ViewPort.Modes & HIRES) scr_dpmx *= 2;
  1867. X    if (wbscr.ViewPort.Modes & LACE) scr_dpmy *= 2;
  1868. X
  1869. X    /* Color map for printer. Add colours ? */
  1870. X    if (!(prtcm = GetColorMap(4))) return nomem(NULL), FALSE;
  1871. X    SetRGB4CM(prtcm, 0, 15, 15, 15);
  1872. X    SetRGB4CM(prtcm, 1, 0, 0, 0);
  1873. X    SetRGB4CM(prtcm, 2, 0, 0, 0);
  1874. X    SetRGB4CM(prtcm, 3, 0, 0, 0);
  1875. X
  1876. X    return TRUE;
  1877. X}
  1878. X
  1879. X/* Free any global resources */
  1880. Xvoid cleanup_grph(void)
  1881. X{
  1882. X    if (prtcm) FreeColorMap(prtcm);
  1883. X}
  1884. X
  1885. SHAR_EOF
  1886. echo "End of archive 4 (of 7)"
  1887. # if you want to concatenate archives, remove anything after this line
  1888. exit
  1889.